package cn.sylinx.horm.core.common;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import cn.sylinx.horm.dialect.Dialect;
import cn.sylinx.horm.exception.HORMException;
import cn.sylinx.horm.type.handler.TypeHandler;

/**
 * ORM通用工具
 * 
 * @author johnhan
 *
 */
@SuppressWarnings("unchecked")
public class OrmUtil {

    public static void setParameter(Dialect dialect, PreparedStatement pst, int index, Object param)
            throws SQLException {

        TypeHandler<Object> handler = null;
        Object actuallyParameter = null;

        if (param == null) {
            handler = dialect.getUnknownTypeHandler();
        } else if (param instanceof TypedParameter) {
            TypedParameter typedParam = (TypedParameter) param;
            actuallyParameter = typedParam.getParameter();
            TypeHandler<?> typeHandler = typedParam.getTypeHandler();

            if (typeHandler != null) {
                handler = (TypeHandler<Object>) typeHandler;
            } else if (typedParam.getParameterType() != null) {
                handler = getTypeHandler(dialect, (Class<Object>) typedParam.getParameterType());
            } else if (actuallyParameter != null) {
                handler = getTypeHandler(dialect, (Class<Object>) actuallyParameter.getClass());
            }

        } else {
            handler = getTypeHandler(dialect, (Class<Object>) param.getClass());
            actuallyParameter = param;
        }

        if (handler != null) {
            handler.setParameter(pst, index, actuallyParameter);
        } else {
            pst.setObject(index, actuallyParameter);
        }
    }

    public static <T> T getResult(Dialect dialect, ResultSet rs, String columnName, Class<T> clz) throws SQLException {
        TypeHandler<T> handler = getTypeHandler(dialect, clz);
        return getResult(rs, columnName, handler);
    }

    public static <T> T getResult(Dialect dialect, ResultSet rs, int columnIndex, Class<T> clz) throws SQLException {
        TypeHandler<T> handler = getTypeHandler(dialect, clz);
        return getResult(rs, columnIndex, handler);
    }

    public static <T> T getResult(Dialect dialect, CallableStatement cs, int columnIndex, Class<T> clz)
            throws SQLException {
        TypeHandler<T> handler = getTypeHandler(dialect, clz);
        return getResult(cs, columnIndex, handler);
    }

    public static <T> T getResult(ResultSet rs, int columnIndex, TypeHandler<T> handler) throws SQLException {
        if (handler != null) {
            return handler.getResult(rs, columnIndex);
        }
        return (T) rs.getObject(columnIndex);
    }

    public static <T> T getResult(ResultSet rs, String columnName, TypeHandler<T> handler) throws SQLException {
        if (handler != null) {
            return handler.getResult(rs, columnName);
        }
        return (T) rs.getObject(columnName);
    }

    public static <T> T getResult(CallableStatement cs, int columnIndex, TypeHandler<T> handler) throws SQLException {

        if (handler != null) {
            return handler.getResult(cs, columnIndex);
        }

        return (T) cs.getObject(columnIndex);
    }

    private static <T> TypeHandler<T> getTypeHandler(Dialect dialect, Class<T> clz) {
        if (dialect == null) {
            throw new HORMException("dialect is null");
        }
        return dialect.crateTypeHandler(clz);
    }
}
